package stream

import (
	"bufio"
	rsEnc "common/encryp/rs_coder"
	"common/encryp/sm4"
	"common/rs"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"strconv"
)

func CutFile(f io.Reader, maxSegmentSize int64, output func([]byte) error) error {
	k := 0
	eofReader := NewEOFReader(f)
	//result := make([][]byte, 0)
	for !eofReader.IsEOF() && !eofReader.HasError() {
		limitReader := io.LimitReader(eofReader, maxSegmentSize)
		k++
		readerBuf := bufio.NewReader(limitReader)
		buf := make([]byte, maxSegmentSize)
		n, readError := readerBuf.Read(buf)
		if readError != nil {
			if eofReader.IsEOF() {
				return nil
			} else {
				fmt.Println(readError)
				return readError
			}
		}
		if err := output(buf[:n]); err != nil {
			return err
		}
	}
	return nil
}

func CutFiles(inFile string, maxSegmentSize int64, output func(reader io.Reader) error) error {
	fp, err := os.Open(inFile)
	if err != nil {
		return err
	}
	defer func() {
		_ = fp.Close()
	}()
	fStat, err := fp.Stat()
	if err != nil {
		return err
	}
	fSize := fStat.Size()
	idx := int64(0)
	for {
		offset := idx * maxSegmentSize
		total := offset + maxSegmentSize
		if total > fSize {
			maxSegmentSize = fSize - offset
		}
		sectionReader := io.NewSectionReader(fp, offset, maxSegmentSize)

		if _err := output(sectionReader); _err != nil {
			fmt.Println("CutFiles callback error ", _err)
			return err
		}

		// 读取结束
		if total >= fSize {
			break
		}
		idx++
	}
	return nil
}

func savePieces(pieces *rsEnc.Pieces, sharedDir string) {
	os.MkdirAll(sharedDir, os.ModePerm)
	for k, v := range pieces.Shared {

		sharedFileName := fmt.Sprintf("%s/%d", sharedDir, k)

		w, err := os.OpenFile(sharedFileName, os.O_WRONLY|os.O_CREATE, os.ModePerm)
		if err != nil {
			continue
		}
		w.Write(v)
		w.Close()
	}
	padFile := fmt.Sprintf("%s/%s", sharedDir, "pad")
	w, _ := os.OpenFile(padFile, os.O_WRONLY|os.O_CREATE, os.ModePerm)
	bPad := byte(pieces.PaddingLen)
	w.Write([]byte{bPad})
}

func readPiece(dir string) *rsEnc.Pieces {

	pieces := &rsEnc.Pieces{}
	pieces.Shared = make(map[int][]byte)
	//pieces.PanddingLen = 8

	infos, err := ioutil.ReadDir(dir)
	if err != nil {
		return nil
	}
	for _, info := range infos {
		if info.IsDir() {
			continue
		}
		if info.Name() == "pad" {
			data, _ := ioutil.ReadFile(path.Join(dir, info.Name()))
			if len(data) == 1 {
				pieces.PaddingLen = int(data[0])
				fmt.Println("pieces.PanddingLen", pieces.PaddingLen)
			}
			continue
		}
		pieceNum, err := strconv.Atoi(info.Name())
		if err != nil {
			fmt.Println("strconv.Atoi err")
			continue
		}
		data, err := ioutil.ReadFile(path.Join(dir, info.Name()))
		if err == nil {
			pieces.Shared[pieceNum] = data
		}
	}

	return pieces
}

func EncodeSegment(rs rs.Rs, segmentData, contentKey []byte) (*rsEnc.Pieces, error) {
	//加密数据
	sm4coder := sm4.NewSm4()
	encData, err := sm4coder.Encode(segmentData, contentKey)
	if err != nil {
		return nil, err
	}
	//RS
	rsscheme := rsEnc.NewRSScheme(rs)
	pieceDatas, err := rsscheme.Encode(encData)
	if err != nil {
		return nil, errors.New("rs_coder data  error")
	}
	return pieceDatas, nil
}

func DecodeSegment(pieces *rsEnc.Pieces, rs rs.Rs, key []byte) ([]byte, error) {
	sm4coder := sm4.NewSm4()
	//key := []byte("1234567890abcdef")
	scheme := rsEnc.NewRSScheme(rs)
	segmentEnc, err := scheme.Decode(pieces)
	if err != nil {
		return nil, err
	}
	segment, err := sm4coder.Decode(segmentEnc, key[:])
	if err != nil {
		fmt.Println(" encryption.Decode", err)
		return nil, err
	}
	return segment, nil
}
func ReRS(pieces *rsEnc.Pieces, rs rs.Rs) (*rsEnc.Pieces, error) {
	scheme := rsEnc.NewRSScheme(rs)
	rawData, err := scheme.Decode(pieces)
	if err != nil {
		return nil, err
	}
	return scheme.Encode(rawData)

}
